﻿using Autofac;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Bigger.Study.ConsoleApp.Autofac.Getting_Started
{
    public class GettingStartedExample : IExample
    {
        //The “WriteDate” method asks Autofac for an IDateWriter.
        //Autofac sees that IDateWriter maps to TodayWriter so starts creating a TodayWriter.
        //Autofac sees that the TodayWriter needs an IOutput in its constructor.
        //Autofac sees that IOutput maps to ConsoleOutput so creates a new ConsoleOutput instance.
        //Autofac uses the new ConsoleOutput instance to finish constructing the TodayWriter.
        //Autofac returns the fully-constructed TodayWriter for “WriteDate” to consume.

        private IContainer Container { get; set; }
        public void Execute()
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<ConsoleOutput>().As<IOutput>().SingleInstance();
            builder.RegisterType<TodayWriter>().As<IDateWriter>().SingleInstance();

            //作用域释放的时候可以帮你释放这些组件
            builder.RegisterType<SomeDisposal>().As<ISomeDisposable>();
            //builder.RegisterType<SomeDisposal2>().As<ISomeDisposable>();

            Container = builder.Build();

            ////解析的实例并不是唯一实例，除非设置SingleInstance，如
            ////builder.RegisterType<TodayWriter>().As<IDateWriter>().SingleInstance();
            ////这个作用域适用于嵌套的生命周期。一个使用Per Lifetime 作用域的component在一个 nested lifetime scope内最多有一个实例。
            ////当对象特定于一个工作单元时，这个非常有用。比如，一个HTTP请求，每一个工作单元都会创建一个nested lifetime，如果在每一次HTTP请求中创建一个nested lifetime，那么其他使用 per-lifetime 的component在每次HTTP请求中只会拥有一个实例。如：
            ////builder.RegisterType<TodayWriter>().As<IDateWriter>().SingleInstance().InstancePerLifetimeScope();

            var writer1 = Container.Resolve<IDateWriter>();
            var writer2 = Container.Resolve<IDateWriter>();
            Console.WriteLine(Object.ReferenceEquals(writer1, writer2));

            // The WriteDate method is where we'll make use
            // of our dependency injection. We'll define that
            // in a bit.
            WriteDate();

            //有些组件可能需要释放（例如实现了IDisposable接口）- 当作用域释放的时候可以帮你释放这些组件。
            ISomeDisposable someDisposable = null;
            using (var scope = Container.BeginLifetimeScope())
            {
                //在作用域内同一个实例，不同作用域不同实例\

                someDisposable = scope.Resolve<ISomeDisposable>();

                //IEnumerable<ISomeDisposable> someDisposableList= scope.Resolve<IEnumerable<ISomeDisposable>>();
                someDisposable.DoSomeThing();
            }
        }

        public void WriteDate()
        {
            //同一作用域同一个实例，不同作用域不同实例
            //builder.RegisterType<TodayWriter>().As<IDateWriter>().SingleInstance().InstancePerLifetimeScope();
            IDateWriter writer1;

            IDateWriter writer2;

            // Create the scope, resolve your IDateWriter,
            // use it, then dispose of the scope.
            using (var scope = Container.BeginLifetimeScope())
            {
                writer1 = scope.Resolve<IDateWriter>();
                writer1.WriteDate();

                writer2 = scope.Resolve<IDateWriter>();
                Console.WriteLine(Object.ReferenceEquals(writer1, writer2));
            }
            
            writer1.WriteDate();
            using (var scope = Container.BeginLifetimeScope())
            {
                writer2 = scope.Resolve<IDateWriter>();
                writer2.WriteDate();
            }

            Console.WriteLine(Object.ReferenceEquals(writer1, writer2));
        }
    }
}
